#include<iostream>
#include<fstream>
#include"cal.h"
#include<stack>
#include<queue>
using namespace std;

int main(){

	/*创建输入输出文件*/
	std::ifstream inputFile("input.txt");  
    std::ofstream outputFile("output.txt");  
	
	if (inputFile.is_open() && outputFile.is_open()){
		char c;
		/*读入文件input.txt的数据*/
		while(inputFile.get(c)){
			
			stack<char> ops;//运算符栈
			queue<char> exp;//表达式队列

			/*判断是否重复输入小数点,读入第一个小数点时为true*/
			bool point = false;	

			/*判断表达式是否合法,合法时为true*/
			bool is_legal = true;

			/*判断括号内是否有数,有数时为true*/
			bool has_digit = true;	

			/**
			 * @brief 判断当前是否可能输入正/负数(即在数字前加正/负号)
			 * 
			 * 这种情况出现在两种地方:
			 * 	1.括号内部,例如"3*(-1)";
			 * 	2.中缀表达式开头,例如"-2+3".
			 * 根据不同情况设立不同的变量如下:
			 * 	1.p_or_n:当读到左括号时为true,读到右括号或数时为false
			 * 	2.init_pn:初始值为true,当读到第一个表达式合法字符
			 * 	  (运算符,括号,数字)时为false.
			 * 需要说明的是,输入+或-合法,输入*或/就要报错.
			 */
			bool p_or_n = false;	
			bool init_pn = true;	

			/**
			 * @brief 标记上一个读入的表达式合法字符
			 * 
			 * 变量名last标记上一个输入的表达式合法字符
			 * 需要做的事情有两件:
			 * 	1.判断一个运算符后面是否有数字出现
			 * 	  (1)若先出现另一个运算符,报错
			 *    (2)若先出现左括号,则不需要标记该运算符
			 * 	  (3)若先出现右括号,报错
			 *    (4)若出现回车字符,报错
			 * 	2.判断左括号前面是什么,有括号后面是什么
			 *    (1)若左括号前面是数字或右括号,其省略了'*',
			 * 		 需要手动push到队列中
			 * 	  (2)若有括号后面是数字,报错.
			 */
			int num = 0, op = 1, r_bracket = 2;	
			int last = -1;	//赋初值-1	
			
			while(true){		
				/*读到回车字符,中断该行循环*/						
				if(c == '\n'){
					/*运算符后遇到回车判断*/
					if(last == op){
						outputFile << "Error! No number after '";
						outputFile << ops.top() << "' !\n";
						is_legal = false;
					}
					break;
				}

				/*读到浮点数的数字部分*/
				if(c >= '0' && c <= '9'){
					/*上一个有效字符是右括号,报错*/
					if(last == r_bracket){
						outputFile << "Error! Number cannot follow ";
						outputFile << "the right bracket!\n";
						is_legal = false;
						break;
					}

					exp.push(c);//push到队列中

					/*读到数字,若已读左括号,则其内必有数*/
					if(!has_digit){
						has_digit = true;
					}
					
					p_or_n = false;	//读到数字部分,不可能再加正/负号
					init_pn = false;//读到第一个有效字符,设为false

					last = num;	//标记last的对应类型是数字
				}

				/*读到浮点数的小数点部分*/
				else if(c == '.'){
					/*上一个有效字符是右括号,报错*/
					if(last == r_bracket){
						outputFile << "Error! Number cannot follow ";
						outputFile << "the right bracket!\n";
						is_legal = false;
						break;
					}

					/*若浮点数还未存入小数点,则存入,并标记point*/
					if(!point){
						exp.push(c);
						point = true;
					}
					/*若浮点数已存入一个小数点,则报错*/
					else{
						outputFile << "Error! Extra decimal point!";
						outputFile << endl;
						is_legal = false;
						break;
					}

					p_or_n = false;	//读到数字部分,不可能再加正/负号
					init_pn = false;//读到第一个有效字符,设为false

					last = num;	//标记last的对应类型是数字
				}

				/*读到左括号*/
				else if(c == '('){
					/*左括号前面是数字或者右括号,手动push'*'到队列中*/
					if(last == num || last == r_bracket){
						ops.push('*');
						exp.push(' ');	//人为添加空格,
										//方便间隔每个浮点数
					}

					ops.push(c);	//左括号入栈

					has_digit = false;	//开始观察括号里有没有数
					
					p_or_n = true;	//重遇左括号,表明之前没输入过负数
					init_pn = false;//如果先输括号,则不需要此帮助了

					last = -1;	//遇左括号,赋初值-1.
								//同时说明先前没有连续输入两次运算符
				}

				/*读到右括号*/
				else if(c == ')'){
					/*括号内没有读取到数字,报错*/
					if(!has_digit){
						outputFile << "Error! Empty brackets!";
						outputFile << endl;
						is_legal = false;
						break;
					}

					/*运算符后面跟右括号,报错*/
					if(last == op){
						outputFile << "Error! No number after '";
						outputFile << ops.top() <<"' in the brackets!\n";
						is_legal = false;
						break;
					}

					p_or_n = false;	//遇到右括号,表明有正/负数也应当输入完成

					exp.push(' ');	//人为添加空格,方便间隔每个浮点数

					/*将括号内包含的运算符存入表达式队列*/
					while(!ops.empty() && ops.top() != '('){
						exp.push(ops.top());
						ops.pop();
					}

					/*若中断原因是栈为空,说明没有左括号,报错*/
					if(ops.empty()){
						outputFile << "Error! Extra right bracket!";
						outputFile << endl;
						is_legal = false;
						break;
					}

					ops.pop();	//删除左括号

					last = r_bracket;	//标记last的对应类型是右括号
				}

				/*读到乘除运算符*/
				else if(c == '*' || c == '/'){
					/*若它是第一个有效表达式字符,报错*/
					if(init_pn){
						outputFile << "Error! No number before '";
						outputFile << c << "' !\n";
						is_legal = false;
						break;
					}

					/*若它在左括号后是第一个有效表达式字符,报错*/
					if(p_or_n && ops.top() == '('){
						outputFile << "Error! No number before '";
						outputFile << c << "' in the brackets!\n";
						is_legal = false;
						break;
					}

					/*若上一个有效字符也是运算符,报错*/
					if(last == op){
						outputFile << "Error! Extra '" << c;
						outputFile << "'!\n";
						is_legal = false;
						break;
					}

					exp.push(' ');	//人为添加空格,方便间隔每个浮点数

					/*将同级运算符(乘/除)存入表达式队列*/
					if(!ops.empty()){
						while(!ops.empty() && 
							(ops.top() == '*' || ops.top() == '/')){
							exp.push(ops.top());
							ops.pop();
						}
					}

					ops.push(c);//将本身存入栈中,待后续清除

					point = false;	//读到运算符,重新计算小数点个数

					last = op;	//标记last的对应类型是运算符
				}

				/*读到加减运算符*/
				else if(c == '+' || c == '-'){
					/*若上一个有效字符也是运算符,报错*/
					if(last == op){
						outputFile << "Error! Extra '" << c;
						outputFile << "'!\n";
						is_legal = false;
						break;
					}				

					/*若它是第一个有效表达式字符,视为正/负数处理*/
					if(init_pn){
						exp.push('0');	//手动push队列'0',
										//视作一次运算过程
						init_pn = false;//读取到有效字符,此变量无帮助了
					}

					/*若它在左括号后是第一个有效表达式字符,视为正/负数处理*/
					if(p_or_n && ops.top() == '('){
						exp.push('0');
					}

					exp.push(' ');	//人为添加空格,方便间隔每个浮点数

					/**
					 * 加减运算优先级低, 所以清空全部运算符,
					 * 直到遇到左括号或者空栈.
					 */
					if(!ops.empty()){
						while(!ops.empty() && ops.top() != '('){
							exp.push(ops.top());
							ops.pop();
						}
					}

					ops.push(c);//将本身存入栈中,待后续清除

					point = false;	//读到运算符,重新计算小数点个数
					
					last = op;	//标记last的对应类型是运算符	
				}

				inputFile.get(c);	//对其他字符不作处理
									//完成读取字符操作,继续读入
			}

			/**
			 * 输入完毕, 但操作符栈中可能还有运算符,
			 * 全部输出到后缀表达式队列中
			 */
			if (is_legal && !ops.empty()){
				while (!ops.empty()){
					/*没有右括号的情况下出现左括号,报错*/
					if(ops.top() == '('){
						outputFile << "Error! Extra left bracket!";
						outputFile << endl;
						is_legal = false;
						break;
					}

					exp.push(' ');	//在添加运算符之前人为添加空格
									
					exp.push(ops.top());
					ops.pop();
				}
			}

			/*若表达式合法,输出后缀表达式
			if(is_legal){
				while (!exp.empty())
				{
					outputFile << exp.front();
					exp.pop();
				}
				outputFile << endl;
			}*/
	
			/*若表达式合法,输出其值*/
			if(is_legal){
				outputFile << calculate(exp) << endl;
			}

			/*若表达式非法,排掉该行非法表达式的其他输入内容*/
			else if(c != '\n'){
				while(inputFile.get(c)){
					if(c == '\n')
						break;
				}
			}			
		}

		/*关闭文件*/
		inputFile.close();  
        outputFile.close();  
  
        cout << "数据已成功写入 output.txt" << endl;
	}
	else{  
        cout << "无法打开文件" << endl;  
    }  
	return 0;
}